package com.ipan.kits.number;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.Arrays;

import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.Validate;

/**
 * {@linkplain BigDecimal}工具封装，更加便捷的计算类
 *
 * @author iPan
 * @date 2019-05-20
 */
public final class BigDecimalWrapper {

    private BigDecimal result;

    private BigDecimalWrapper() {

    }

    public static BigDecimalWrapper wrapper(int value) {
        BigDecimalWrapper bigDecimalWrapper = new BigDecimalWrapper();
        bigDecimalWrapper.result = new BigDecimal(value);
        return bigDecimalWrapper;
    }

    public static BigDecimalWrapper wrapper(float value) {
        BigDecimalWrapper bigDecimalWrapper = new BigDecimalWrapper();
        bigDecimalWrapper.result = new BigDecimal(value);
        return bigDecimalWrapper;
    }

    public static BigDecimalWrapper wrapper(double value) {
        BigDecimalWrapper bigDecimalWrapper = new BigDecimalWrapper();
        bigDecimalWrapper.result = new BigDecimal(value);
        return bigDecimalWrapper;
    }

    public static BigDecimalWrapper wrapper(long value) {
        BigDecimalWrapper bigDecimalWrapper = new BigDecimalWrapper();
        bigDecimalWrapper.result = new BigDecimal(value);
        return bigDecimalWrapper;
    }

    public static BigDecimalWrapper wrapper(String value) {
        Validate.notNull(value, "The value is null");
        BigDecimalWrapper bigDecimalWrapper = new BigDecimalWrapper();
        bigDecimalWrapper.result = new BigDecimal(value);
        return bigDecimalWrapper;
    }

    public static BigDecimalWrapper wrapper(BigDecimal value) {
        Validate.notNull(value, "The value is null");
        BigDecimalWrapper bigDecimalWrapper = new BigDecimalWrapper();
        bigDecimalWrapper.result = value;
        return bigDecimalWrapper;
    }

    //region 加法

    public BigDecimalWrapper add(int augend) {
        result = result.add(new BigDecimal(augend));
        return this;
    }

    public BigDecimalWrapper add(float augend) {
        result = result.add(new BigDecimal(augend));
        return this;
    }

    public BigDecimalWrapper add(double augend) {
        result = result.add(new BigDecimal(augend));
        return this;
    }

    public BigDecimalWrapper add(long augend) {
        result = result.add(new BigDecimal(augend));
        return this;
    }

    public BigDecimalWrapper add(String augend) {
        result = result.add(new BigDecimal(augend));
        return this;
    }

    public BigDecimalWrapper add(int... augends) {
        if (ArrayUtils.isNotEmpty(augends)) {
            for (int augend : augends) {
                result = result.add(new BigDecimal(augend));
            }
        }
        return this;
    }

    public BigDecimalWrapper add(float... augends) {
        if (ArrayUtils.isNotEmpty(augends)) {
            for (float augend : augends) {
                result = result.add(new BigDecimal(augend));
            }
        }
        return this;
    }

    public BigDecimalWrapper add(double... augends) {
        if (ArrayUtils.isNotEmpty(augends)) {
            for (double augend : augends) {
                result = result.add(new BigDecimal(augend));
            }
        }
        return this;
    }

    public BigDecimalWrapper add(long... augends) {
        if (ArrayUtils.isNotEmpty(augends)) {
            for (long augend : augends) {
                result = result.add(new BigDecimal(augend));
            }
        }
        return this;
    }

    //endregion

    //region 减法

    public BigDecimalWrapper add(String... augends) {
        if (ArrayUtils.isNotEmpty(augends)) {
            Arrays.stream(augends).map(BigDecimal::new).forEach(bd -> result = result.add(bd));
        }
        return this;
    }

    public BigDecimalWrapper subtract(int value) {
        result = result.subtract(new BigDecimal(value));
        return this;
    }

    public BigDecimalWrapper subtract(float value) {
        result = result.subtract(new BigDecimal(value));
        return this;
    }

    public BigDecimalWrapper subtract(double value) {
        result = result.subtract(new BigDecimal(value));
        return this;
    }

    public BigDecimalWrapper subtract(long value) {
        result = result.subtract(new BigDecimal(value));
        return this;
    }

    public BigDecimalWrapper subtract(int... subtrahend) {
        if (ArrayUtils.isNotEmpty(subtrahend)) {
            for (long aSubtrahend : subtrahend) {
                result = result.subtract(new BigDecimal(aSubtrahend));
            }
        }
        return this;
    }

    public BigDecimalWrapper subtract(float... subtrahend) {
        if (ArrayUtils.isNotEmpty(subtrahend)) {
            for (float aSubtrahend : subtrahend) {
                result = result.subtract(new BigDecimal(aSubtrahend));
            }
        }
        return this;
    }

    public BigDecimalWrapper subtract(double... subtrahend) {
        if (ArrayUtils.isNotEmpty(subtrahend)) {
            for (double aSubtrahend : subtrahend) {
                result = result.subtract(new BigDecimal(aSubtrahend));
            }
        }
        return this;
    }

    public BigDecimalWrapper subtract(long... subtrahend) {
        if (ArrayUtils.isNotEmpty(subtrahend)) {
            for (long aSubtrahend : subtrahend) {
                result = result.subtract(new BigDecimal(aSubtrahend));
            }
        }
        return this;
    }

    //endregion

    //region 乘法

    public BigDecimalWrapper subtract(String... subtrahend) {
        if (ArrayUtils.isNotEmpty(subtrahend)) {
            for (String aSubtrahend : subtrahend) {
                result = result.subtract(new BigDecimal(aSubtrahend));
            }
        }
        return this;
    }

    public BigDecimalWrapper multiply(int value) {
        result = result.multiply(new BigDecimal(value));
        return this;
    }

    public BigDecimalWrapper multiply(float value) {
        result = result.multiply(new BigDecimal(value));
        return this;
    }

    public BigDecimalWrapper multiply(double value) {
        result = result.multiply(new BigDecimal(value));
        return this;
    }

    public BigDecimalWrapper multiply(long value) {
        result = result.multiply(new BigDecimal(value));
        return this;
    }

    public BigDecimalWrapper multiply(String value) {
        result = result.multiply(new BigDecimal(value));
        return this;
    }

    public BigDecimalWrapper multiply(int... multiplicands) {
        if (ArrayUtils.isNotEmpty(multiplicands)) {
            for (int multiplicand : multiplicands) {
                result = result.multiply(new BigDecimal(multiplicand));
            }
        }
        return this;
    }

    public BigDecimalWrapper multiply(float... multiplicands) {
        if (ArrayUtils.isNotEmpty(multiplicands)) {
            for (float multiplicand : multiplicands) {
                result = result.multiply(new BigDecimal(multiplicand));
            }
        }
        return this;
    }

    public BigDecimalWrapper multiply(double... multiplicands) {
        if (ArrayUtils.isNotEmpty(multiplicands)) {
            for (double multiplicand : multiplicands) {
                result = result.multiply(new BigDecimal(multiplicand));
            }
        }
        return this;
    }

    public BigDecimalWrapper multiply(long... multiplicands) {
        if (ArrayUtils.isNotEmpty(multiplicands)) {
            for (long multiplicand : multiplicands) {
                result = result.multiply(new BigDecimal(multiplicand));
            }
        }
        return this;
    }

    //endregion

    //region 除法

    public BigDecimalWrapper multiply(String... multiplicands) {
        if (ArrayUtils.isNotEmpty(multiplicands)) {
            for (String multiplicand : multiplicands) {
                result = result.multiply(new BigDecimal(multiplicand));
            }
        }
        return this;
    }

    public BigDecimalWrapper divide(int value) {
        result = result.divide(new BigDecimal(value));
        return this;
    }

    public BigDecimalWrapper divide(int value, RoundingMode roundingMode) {
        result = result.divide(new BigDecimal(value), roundingMode);
        return this;
    }

    public BigDecimalWrapper divide(int value, int scale) {
        result = result.divide(new BigDecimal(value), scale);
        return this;
    }

    public BigDecimalWrapper divide(int value, int scale, RoundingMode roundingMode) {
        result = result.divide(new BigDecimal(value), scale, roundingMode);
        return this;
    }

    public BigDecimalWrapper divide(float value) {
        return divide(value, RoundingMode.UNNECESSARY);
    }

    public BigDecimalWrapper divide(float value, RoundingMode roundingMode) {
        result = result.divide(new BigDecimal(value), roundingMode);
        return this;
    }

    public BigDecimalWrapper divide(float value, int scale) {
        return divide(value, scale, RoundingMode.UNNECESSARY);
    }

    public BigDecimalWrapper divide(float value, int scale, RoundingMode roundingMode) {
        result = result.divide(new BigDecimal(value), scale, roundingMode);
        return this;
    }

    public BigDecimalWrapper divide(double value) {
        return divide(value, RoundingMode.UNNECESSARY);
    }

    public BigDecimalWrapper divide(double value, RoundingMode roundingMode) {
        result = result.divide(new BigDecimal(value), roundingMode);
        return this;
    }

    public BigDecimalWrapper divide(double value, int scale) {
        return divide(value, scale, RoundingMode.UNNECESSARY);
    }

    public BigDecimalWrapper divide(double value, int scale, RoundingMode roundingMode) {
        result = result.divide(new BigDecimal(value), scale, roundingMode);
        return this;
    }

    public BigDecimalWrapper divide(long value) {
        return divide(value, RoundingMode.UNNECESSARY);
    }

    public BigDecimalWrapper divide(long value, RoundingMode roundingMode) {
        result = result.divide(new BigDecimal(value), roundingMode);
        return this;
    }

    public BigDecimalWrapper divide(long value, int scale) {
        return divide(value, scale, RoundingMode.UNNECESSARY);
    }

    public BigDecimalWrapper divide(long value, int scale, RoundingMode roundingMode) {
        result = result.divide(new BigDecimal(value), scale, roundingMode);
        return this;
    }

    public BigDecimalWrapper divide(String value) {
        return divide(value, RoundingMode.UNNECESSARY);
    }

    public BigDecimalWrapper divide(String value, RoundingMode roundingMode) {
        result = result.divide(new BigDecimal(value), roundingMode);
        return this;
    }

    public BigDecimalWrapper divide(String value, int scale) {
        return divide(value, scale, RoundingMode.UNNECESSARY);
    }

    public BigDecimalWrapper divide(String value, int scale, RoundingMode roundingMode) {
        result = result.divide(new BigDecimal(value), scale, roundingMode);
        return this;
    }

    public BigDecimalWrapper divide(int... divisors) {
        if (ArrayUtils.isNotEmpty(divisors)) {
            for (int divisor : divisors) {
                result = result.divide(new BigDecimal(divisor), RoundingMode.UNNECESSARY);
            }
        }
        return this;
    }

    public BigDecimalWrapper divide(float... divisors) {
        if (ArrayUtils.isNotEmpty(divisors)) {
            for (float divisor : divisors) {
                result = result.divide(new BigDecimal(divisor), RoundingMode.UNNECESSARY);
            }
        }
        return this;
    }

    public BigDecimalWrapper divide(double... divisors) {
        if (ArrayUtils.isNotEmpty(divisors)) {
            for (double divisor : divisors) {
                result = result.divide(new BigDecimal(divisor), RoundingMode.UNNECESSARY);
            }
        }
        return this;
    }

    public BigDecimalWrapper divide(long... divisors) {
        if (ArrayUtils.isNotEmpty(divisors)) {
            for (long divisor : divisors) {
                result = result.divide(new BigDecimal(divisor), RoundingMode.UNNECESSARY);
            }
        }
        return this;
    }


    //endregion

    public BigDecimalWrapper divide(String... divisors) {
        if (ArrayUtils.isNotEmpty(divisors)) {
            for (String divisor : divisors) {
                result = result.divide(new BigDecimal(divisor), RoundingMode.UNNECESSARY);
            }
        }
        return this;
    }

    public BigDecimalWrapper setScale(int scale) {
        result = result.setScale(scale, BigDecimal.ROUND_UNNECESSARY);
        return this;
    }

    //region 返回结果

    public BigDecimalWrapper setScale(int scale, RoundingMode roundingMode) {
        result = result.setScale(scale, roundingMode);
        return this;
    }

    public BigDecimal getResult() {
        return result;
    }

    public int getResult2Int() {
        return result.intValue();
    }

    public long getResult2Long() {
        return result.longValue();
    }

    public double getResult2Double() {
        return result.doubleValue();
    }

    //endregion

    public static void main(String[] args) {
        double result = BigDecimalWrapper.wrapper(1).add(2, 3, 4, 5, 5)
                .divide(2.25, 1, RoundingMode.HALF_UP)
                .getResult2Double();
        System.out.println("result = " + result);
    }

}
